package com.demo.arch.datapulsedemo.v3_reliable.core;

import com.demo.arch.datapulsedemo.common.TaskResult;
import com.demo.arch.datapulsedemo.v2_pipeline.core.PipelineContext;
import com.demo.arch.datapulsedemo.v2_pipeline.core.StepExecutionException;
import com.demo.arch.datapulsedemo.v2_pipeline.core.StepHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 可靠的Pipeline（V3版本）
 * 
 * 增强特性：
 * 1. 断点续跑 - 每步保存状态
 * 2. 幂等执行 - 自动跳过已完成步骤
 * 3. 部分重试 - 邮件部分失败可以重试
 * 
 * @author DataPulse Team
 */
@Slf4j
@Component
public class ReliablePipeline {

  private final List<StepHandler> steps;
  private final ContextStorage contextStorage;

  @Autowired
  public ReliablePipeline(List<StepHandler> steps, ContextStorage contextStorage) {
    // 按Order排序
    this.steps = steps.stream()
        .sorted(Comparator.comparingInt(StepHandler::getOrder))
        .collect(Collectors.toList());

    this.contextStorage = contextStorage;

    log.info("ReliablePipeline初始化完成，共{}个步骤:", this.steps.size());
    for (int i = 0; i < this.steps.size(); i++) {
      StepHandler step = this.steps.get(i);
      log.info("  步骤{}: {} (Order={})", i + 1, step.getName(), step.getOrder());
    }
  }

  /**
   * 执行任务
   */
  public TaskResult execute(String reportType) {
    // 生成任务ID
    String taskId = generateTaskId();

    // 初始化上下文
    PipelineContext context = new PipelineContext(reportType);
    context.setTaskId(taskId);
    context.setCreateTime(LocalDateTime.now());
    context.setCurrentStep(0);

    return executeWithContext(context);
  }

  /**
   * 使用现有上下文执行（用于重试）
   */
  public TaskResult executeWithContext(PipelineContext context) {
    log.info("========== V3 ReliablePipeline 任务开始 ==========");
    log.info("任务ID: {}", context.getTaskId());
    log.info("报表类型: {}", context.getReportType());
    log.info("当前步骤: {}", context.getCurrentStep());
    log.info("执行步骤: {}", steps.stream().map(StepHandler::getName).collect(Collectors.joining(" → ")));

    long startTime = System.currentTimeMillis();

    try {
      // 依次执行每个步骤
      for (int i = 0; i < steps.size(); i++) {
        StepHandler step = steps.get(i);
        executeStep(step, context, i + 1);

        // 更新当前步骤
        context.setCurrentStep(i + 1);

        // 保存上下文（每步执行完都保存）
        contextStorage.save(context);
      }

      long duration = System.currentTimeMillis() - startTime;
      log.info("========== V3 ReliablePipeline 任务完成，耗时: {}ms ==========", duration);

      // 任务完成，删除上下文
      contextStorage.delete(context.getTaskId());

      return TaskResult.success("Pipeline执行成功", context);

    } catch (Exception e) {
      long duration = System.currentTimeMillis() - startTime;
      log.error("========== V3 ReliablePipeline 任务失败，耗时: {}ms ==========", duration, e);

      // 记录错误信息
      context.setErrorMessage(e.getMessage());
      contextStorage.save(context);

      return TaskResult.fail("Pipeline执行失败: " + e.getMessage());
    }
  }

  /**
   * 执行单个步骤
   */
  private void executeStep(StepHandler step, PipelineContext context, int stepNumber) {
    log.info("--- 步骤{}/{}: {} ---", stepNumber, steps.size(), step.getName());

    // 幂等性检查
    if (!step.shouldExecute(context)) {
      log.info("--- 步骤{}: {} 已完成，跳过执行 ---", stepNumber, step.getName());
      return;
    }

    long startTime = System.currentTimeMillis();

    try {
      // 执行步骤
      step.handle(context);

      long duration = System.currentTimeMillis() - startTime;
      log.info("--- 步骤{}: {} 执行成功，耗时: {}ms ---", stepNumber, step.getName(), duration);

    } catch (StepExecutionException e) {
      log.error("--- 步骤{}: {} 执行失败 ---", stepNumber, step.getName());
      throw e;

    } catch (Exception e) {
      log.error("--- 步骤{}: {} 执行异常 ---", stepNumber, step.getName());
      throw new StepExecutionException(step.getName(), "未知异常", e);
    }
  }

  /**
   * 从断点恢复任务
   */
  public TaskResult recover(String taskId) {
    // 加载上下文
    PipelineContext context = contextStorage.load(taskId);

    if (context == null) {
      return TaskResult.fail("任务不存在: " + taskId);
    }

    log.info("从断点恢复任务: {}, 当前步骤: {}", taskId, context.getCurrentStep());

    // 执行
    return executeWithContext(context);
  }

  /**
   * 生成任务ID
   */
  private String generateTaskId() {
    return "TASK_V3_" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
  }
}
